import java.net.*;
import java.io.*;
import java.util.*;
import javax.swing.text.*;
import javax.swing.text.html.*;
import javax.swing.text.html.parser.*;

import org.apache.commons.lang.StringEscapeUtils;


public class feedParse {
    
    /**
     * Flags for identifying data 
     */
    
    int itemcontents;	//Itemcontents is 4 for Time, 3 is for Title, 2 for Source, and 1 for decription
    int bold;
    int image;
    int itemtitle;
    int boldD;
    int stop;
    
    /**
     * ArrayList storing news articles + current article object
     */
    ArrayList<article> articles;
    article news;
    
    private int debug = 0;
    
    public feedParse()
    {
    	itemcontents = 0;
    	bold = 0;
    	image=0;
    	itemtitle=0;
    	
    	articles =new ArrayList<article>();;
    	news = new article();
    }
    
    public ArrayList<article> parsePage(String s)
    {
    	URL u;
        Reader r;
        
    	itemcontents = 0;
    	bold = 0;
    	boldD = 0;
    	image=0;
    	itemtitle=0;
    	
    	stop=0;
    	
    	articles =new ArrayList<article>();;
    	news = new article();
            	
        try {
        	u = new URL(s);
            //Object content = u.getContent();
        	
        	URLConnection conn = u.openConnection();  
        	    
        	conn.addRequestProperty("user-agent", "Mozilla/4.0");  
            r = new InputStreamReader((InputStream) conn.getInputStream());

            HTMLEditorKit.Parser parser;
            parser = new ParserDelegator();
            RSSParser lp = new RSSParser();
            parser.parse(r, lp, true);
        }
        catch (Exception e) {
            System.err.println("Error: " + e);
        }
        
        //If Empty List then simply return
        int size = articles.size();
        if(size<1) return articles;
        
        //Add last article
        if(!news.equals(articles.get(size-1))) articles.add(news);
        
        //Print test
        if(debug==1) printArt();
        
        return articles;
    }
    
    public void extractDesc(String desc)
    {
    	desc = desc.trim();
		
        Reader r;
        
    	try {
	    	StringBuffer StringBuffer1 = new StringBuffer(desc);
	        ByteArrayInputStream content = new ByteArrayInputStream(StringBuffer1.toString().getBytes("UTF-8"));
	        
	        r = new InputStreamReader((InputStream) content);
	        
	        HTMLEditorKit.Parser parser;
            parser = new ParserDelegator();
            RSSParser lp = new RSSParser();
            parser.parse(r, lp, true);
	        
	        
	        
    	} catch (Exception e) {
    		System.err.println("Error: " + e);
    	}
        
    }
    
    /**
     * Parser for direct RSS feed
     */
    class RSSParser extends HTMLEditorKit.ParserCallback
    {
    	int flag = -1;
    	int d =0;
    	
    	public void handleStartTag(HTML.Tag t, MutableAttributeSet a, int pos) {
    		if(t.toString().equals("title")) flag = 1;
    		if(t.equals(HTML.Tag.FONT)&&(d<1))
    		{
    			try {
	    			String color = (String)a.getAttribute(HTML.Attribute.COLOR);
	    			if(color.equals("#6f6f6f")) d=1;
    			} catch (Exception e) {
    				
    			}
    		}
    		if(t.equals(HTML.Tag.B) && (d>0)) d=4;
    	}
    	
    	public void handleEndTag(HTML.Tag t, int pos) {
    		//if(t.equals(HTML.Tag.FONT)&&(d==2)) d=0;
    	}
    	
    	public void handleText(char[] data,int pos) {
    		//System.out.println(data);
    		
    		String s = new String(data);
    		
    		s = StringEscapeUtils.unescapeHtml(s);
    		
    		if((flag==1) && !s.equals("- Google News"))
    			{
    				news = new article();
    				if(debug==1) System.out.println("TITLE: "+s);
    				news.setTitle(s);
    				flag=2;
    				return;
    			}
    		else if(flag==2)
    		{
    			flag++;
    			return;
    		}
    		else if(flag==3)
    		{
    			//System.out.println(s.length());
    			//System.out.println(s.substring(3));
    			if(debug==1) System.out.println(s.substring(s.indexOf("=")+1));
    			news.setLink(s.substring(s.indexOf("=")+1));
    			flag++;
    			return;
    		}
    		else if(flag==4)
    		{
    			if(debug==1) System.out.println(s);
    			news.setTime(s);
    			flag++;
    			return;
    		}
    		else if(flag==5)
    		{
    			extractDesc(s);
    			//System.out.println(s);
    			flag=0;
    			return;
    		}
    		else flag=0;
    		
    		if(d==1)
    		{
    			if(debug==1) System.out.println("Source "+s);
    			news.setSource(s);
    			d=2;
    			return;
    		}
    		else if(d==2)
    		{
    			if(debug==1) System.out.println("TExt "+s);
    			news.setDescription(news.getDescription().trim() +" "+ s);
    			if(!articles.contains(news)) articles.add(news);
    			d=3;
    		}
    		else if(d==4)
    		{
    			if(!s.equals("..."))
    			{
    				news.setDescription(news.getDescription() +" "+ s);
    				d=2;
    			}
    			else if(news.getDescription().length()==0) d=2;
    			else d=3;
    		}
    	}
    }
    
    /**
     * Parser for RSS Feed via Feedbucket
     * @author tomalteman
     *
     */
    class CallParser extends HTMLEditorKit.ParserCallback
    {

        public void handleStartTag(HTML.Tag t, MutableAttributeSet a, int pos) {
            handleSimpleTag(t,a,pos);
        }
        
        public void handleEndTag(HTML.Tag t, int pos) {
            if(t.equals(HTML.Tag.A))
            	{
            		image=0;
            		
            		//If reached the end of the title make sure itemcontent is 2
            		if((itemcontents==3) && (news.getTitle().length()>0)) itemcontents = 2;
            	}
        }

        public void handleSimpleTag(HTML.Tag t, MutableAttributeSet a, int pos) {
          
        	if(debug==1) System.out.println(t);
        	//Check to see if item title is set
        	if (itemtitle==1)
        	{
        		stop=0;
        		String link = (String)a.getAttribute(HTML.Attribute.HREF);
        		if(link==null) return;
        		else
        		{
        			//System.out.println("LINK IS "+link);
        			
        			//Initialise new news article and insert link covnerting it from form given by google
        			link = getLink(link);
        			news = new article(link);
        			
        			//System.out.println("ACUTAL LINK IS "+link);
        			itemtitle=0;
        		}
        	}
        	
        	//Check Bold for time
        	if (t.equals(HTML.Tag.B) && (itemcontents ==4)) bold=1;
        	
        	//Check Bold for time
        	if (t.equals(HTML.Tag.B) && (itemcontents ==3)) bold=1;
        	
        	//Check if bold for title
        	if (t.equals(HTML.Tag.B) && (itemcontents ==2)) bold=1;
        	
        	//If bold in description
        	if (t.equals(HTML.Tag.B) && (itemcontents < 2) && (bold != 1)) boldD = 1;
        	
        	//Check class
        	String id = (String)a.getAttribute(HTML.Attribute.CLASS);
        	try {
        		if (id.equals("item-contents")) itemcontents = 4;
        		//Check to see if it's item title
        		else if (id.equals("item-title")) itemtitle = 1;
        		
        	} catch (NullPointerException npe)
        	{}
        	
        	try {
    		//Check if img and has a source
    		if (t.equals(HTML.Tag.IMG) && (itemcontents ==3))
    			{
    				String src = (String)a.getAttribute(HTML.Attribute.SRC);
    				if(src.length() > 0) image = 1;
    			}
        	} catch (NullPointerException npe)
        	{}
    	
        	
        }
        
        public void handleText(char[] data,int pos)
        {
        	System.out.println(data);
        	
        	//If no longer should be looking to store news
        	if(stop==1) return;
        	
        	//Test that its not ...
        	/*if((new String(data)).equals("..."))
        	{
        		boldD=0;
        		return;
        	}*/
        	
        	//If text is too short then clearly not valid
        	if((image==1)) 
        		{
        			//System.out.println("IMAGE NAME IS "+ new String(data));
        			image = 0;
        			return;
        		}
        	
        	//If text is too short then clearly not valid
        	if(data.length < 3) return;
        	
        	//System.out.println(new String(data));
        	
        	//Get Time of Article
        	if((itemcontents ==4) && (bold==1))
        	{
        		//Add to article list
        		articles.add(news);
        		
        		//Set time for current news item
        		news.setTime(new String(data));
        		
        		//System.out.println("TIME IS "+ new String(data));
        		bold=0;
        		itemcontents--;
        		return;
        	}
        	
        	//Gets Title
        	if((itemcontents == 3))
        	{
        		if(bold==1)
        		{
        			news.setTitle(news.getTitle() + new String(data));
        			bold = 0;
        			return;
        		}
        		
        		//Set title for current news item
        		news.setTitle(news.getTitle() + new String(data));
        		
        		//System.out.println("TITLE IS "+new String(data));
        		itemcontents--;
        		return;
        	}
        	
        	//Gets source
        	if((itemcontents == 2))
        	{	
        		if((bold==1))
        		{
        			//Check if ... to be added
        			if(new String(data).equals("..."))
        			{
	        			//Add ' ...' to indicate short title
	        			news.setTitle(news.getTitle()+" ...");
	        			
	        			//System.out.println("Add ...");
	        			itemcontents=2;
        			}
        			else 
        			{
        				//If not ... then still part of title
        				news.setTitle(news.getTitle()+new String(data));
        				itemcontents=3;
        			}

        			bold=0;
            		return;
        		}
        		
        		//Set source for current news item
        		news.setSource(new String(data));
        		
        		//System.out.println("SOURCE IS "+new String(data));
        		itemcontents--;
        		return;
        	}
        	
        	//Get bold decsription text
        	if((boldD == 1) && (itemcontents != 0))
        	{
        		if(!(new String(data)).equals("..."))
        		{
        			news.setDescription(news.getDescription() + new String(data));
        			//System.out.println("DESCRIPTION IS "+new String(data));
            		itemcontents = 1;
        		}
        		else if((news.getDescription()).length() > 0)
        			{
        				itemcontents = 0;
        				stop=1;
        			}
        		boldD = 0;
        		return;
        	}
        	
        	//Get description
        	if(itemcontents == 1)
        	{
        		//Set description of news article and then add to array
        		news.setDescription(news.getDescription() + new String(data));	
        		
        		//System.out.println("DESCRIPTION IS "+new String(data));
        		//System.out.println();
        		itemcontents=-1;
        	}
        }
    } 
    
    /**
     * Acquire real link from that given by google news
     * Removing hex and inserting ascii
     * @param link
     * @return
     */
    private String getLink(String link)
    {
    	
    	//Find start index
    	int index = link.indexOf("url=") + 4;
    	int end = link.length();
    	int i=0;
    	
    	//Find end index
    	if(link.indexOf(".html") > (-1)) end = link.indexOf(".html") + 5;
    	else if(link.indexOf(".story") > (-1)) end = link.indexOf(".story") + 6;
    	else if(link.indexOf("&cid=") > -1) end =  link.indexOf("&cid=");
    	
    	//Convert to char array
    	char[] temp = link.toCharArray();
    	char[] res = new char[temp.length];
    	
    	//Copy to new string
    	while(index<end)
    	{
    		if(temp[index]=='%')
    		{
    			res[i] = hexToChar(temp[index+1],temp[index+2]);
    			index = index + 3;
    		}
    		else
    		{
    			res[i]=temp[index];
    			index++;
    		}
    		i++;
    	}
    	   	
    	return (new String(res)).substring(0, i);
    }
    
    /**
     * Converts hex string into ascii character
     * @param hex
     * @return
     */
    private char hexToChar(char c1, char c2)
    {
    	char[] ar = {c1,c2};
    	return (char) Integer.parseInt((new String(ar)), 16);
    }
    
    /**
     * 
     * @param args
     */
	public static void main(String[] args) {
		feedParse reader = new feedParse();
		//ArrayList<article> arts = reader.parsePage("http://proxy-online.com/browse.php?u=http%3A%2F%2Fnews.google.com%2Fnews%3Fpz%3D1%26ned%3Dus%26hl%3Den%26geo%3Ddurham%26scoring%3Dn%26output%3Drss&b=20");
		ArrayList<article> arts = reader.parsePage("http://news.google.com/news?pz=1&ned=us&hl=en&geo=abergavenny&q=business&output=rss");
		reader.printArt();
	}
	
	/**
	 * Print article to terminal
	 */
	private void printArt()
	{
		article art;
		System.out.println("Size is "+articles.size());
		for(int i=0;i<articles.size();i++)
		{
			art = articles.get(i);
			System.out.println("TITLE IS "+art.getTitle());
			System.out.println("TIME IS "+art.getTime());
			System.out.println("LINK IS "+art.getLink());
			System.out.println("SOURCE IS "+art.getSource());
			System.out.println("DESCRIPTION IS "+art.getDescription());
			System.out.println();
		}
	}
	
    /**
     * Error algorithm
     */
    private static void err(String s)
    {
        //Error printing
        System.err.println(s);
        System.exit(1);        
    }
}
